using System;
using System.Windows.Forms;
using System.Globalization;
using System.IO;
using System.Collections;
using System.Net;
using Transferomatic.Views;
using System.Diagnostics;
using System.Drawing;
using System.Deployment.Application;
using System.ComponentModel;
using Transferomatic.Enumerators;

namespace Transferomatic.ApplicationControllers
{
    public partial class Controller
    {
        #region Members
        private MainView _MainView;
        #endregion

        #region Methods
        private void MainView_Show()
        {
            // Instantiate an instance
            this._MainView = new MainView();

            this._MainView.buttonAddFileTransfer.Click +=
                new EventHandler(MainView_buttonAddFileTransfer_Click);
            this._MainView.buttonAddDirectoryTransfer.Click += 
                new EventHandler(MainView_buttonAddDirectoryTransfer_Click);

            this._MainView.buttonPlayAll.Click +=
                new EventHandler(MainView_buttonPlayAll_Click);
            this._MainView.buttonPauseAll.Click +=
                new EventHandler(MainView_buttonPauseAll_Click);
            this._MainView.buttonStopAll.Click +=
                new EventHandler(MainView_buttonStopAll_Click);

            this._MainView.buttonSettings.Click +=
                new EventHandler(MainView_buttonSettings_Click);
            this._MainView.buttonCheckForUpdates.Click +=
                new EventHandler(MainView_buttonCheckForUpdates_Click);

            this._MainView.gridTransfers.MouseUp += 
                new MouseEventHandler(MainView_gridTransfers_MouseUp);
            this._MainView.menuitemEditTransfer.Click +=
                new EventHandler(MainView_menuitemEditTransfer_Click);
            this._MainView.gridTransfers.DoubleClick += 
                new EventHandler(MainView_gridTransfers_DoubleClick);
            this._MainView.menuitemDeleteTransfer.Click += 
                new EventHandler(MainView_menuitemDeleteTransfer_Click);

            this._MainView.NotifyIcon.DoubleClick +=
                new EventHandler(MainView_NotifyIcon_DoubleClick);
            this._MainView.menuitemCheckForUpdates.Click +=
                new EventHandler(MainView_menuitemCheckForUpdates_Click);
            this._MainView.menuitemPlayAll.Click +=
                new EventHandler(MainView_menuitemPlayAll_Click);
            this._MainView.menuitemPauseAll.Click +=
                new EventHandler(MainView_menuitemPauseAll_Click);
            this._MainView.menuitemStopAll.Click +=
                new EventHandler(MainView_menuitemStopAll_Click);
            this._MainView.menuitemExit.Click +=
                new EventHandler(MainView_menuitemExit_Click);

            this._MainView.Resize +=
                new EventHandler(MainView_Resize);
            this._MainView.FormClosing +=
                new FormClosingEventHandler(MainView_FormClosing);
            this._MainView.StatusChanged +=
                new EventHandler(MainView_StatusChanged);

            this._MainView.menuitemEditTransfer.Tag =
                this._MainView.menuitemDeleteTransfer.Tag =
                    this._MainView;
            this._MainView.labelVersion.Text =
                Controller.PublishVersion;

            // Attach the MainView to the Application Context
            this._AppContext.MainForm = this._MainView;

            // Show the form
            this._MainView.Show();

            this.UpdateNotificationView_Show();
        }

        #region Event Handlers
        private void MainView_gridTransfers_MouseUp(
            object sender, 
            MouseEventArgs e)
        {
            Application.DoEvents();

            DataGridView theTransfersGrid =
                sender as DataGridView;
            MainView theParentView =
                theTransfersGrid.FindForm() as MainView;

            if (!theTransfersGrid.SelectedRows.Count.Equals(0))
            {
                TransferAgent theAgent =
                    theTransfersGrid.SelectedRows[0].Tag
                        as TransferAgent;

                theParentView.menuitemEditTransfer.Enabled =
                    theParentView.menuitemDeleteTransfer.Enabled =
                        !theAgent.Status.Equals(TransferAgentStatus.Transferring);
            }
        }

        private void MainView_menuitemDeleteTransfer_Click(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            ToolStripMenuItem theDeleteTransferMenuItem =
                sender as ToolStripMenuItem;
            MainView theParentView =
                theDeleteTransferMenuItem.Tag as MainView;

            switch (MessageBox.Show(
                theParentView,
                "Are you sure you want to remove this transfer?",
                theParentView.Text,
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Warning,
                MessageBoxDefaultButton.Button2))
            {
                case DialogResult.No:
                    Application.DoEvents();
                    return;
            }

            Application.DoEvents();

            for (int i = theParentView.gridTransfers.SelectedRows.Count - 1; i > -1; i--)
            {
                TransferAgent thisAgent =
                    theParentView.gridTransfers.SelectedRows[i].Tag
                        as TransferAgent;

                if (!thisAgent.Status.Equals(TransferAgentStatus.Transferring))
                {
                    theParentView.gridTransfers.Rows.Remove(
                        theParentView.gridTransfers.SelectedRows[i]);
                }
            }

            if (this._MainView.Status.Equals(MainViewStatus.Started))
            {
                this.PlayAll();
            }
        }

        private void MainView_menuitemEditTransfer_Click(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            ToolStripMenuItem theEditTransferMenuItem =
                sender as ToolStripMenuItem;
            MainView theParentView =
                theEditTransferMenuItem.Tag as MainView;

            this.MainView_gridTransfers_DoubleClick(
                theParentView.gridTransfers, e);
        }

        private void MainView_gridTransfers_DoubleClick(
            object sender, 
            EventArgs e)
        {
            Application.DoEvents();

            DataGridView theTransfersGrid =
                sender as DataGridView;
            MainView theParentView =
                theTransfersGrid.FindForm()
                    as MainView;

            for (int i = theParentView.gridTransfers.SelectedRows.Count - 1; i > -1; i--)
            {
                TransferAgent thisAgent =
                    theParentView.gridTransfers.SelectedRows[i].Tag
                        as TransferAgent;

                if (!thisAgent.Status.Equals(TransferAgentStatus.Transferring))
                {
                    switch (thisAgent.TransferType)
                    {
                        case TransferAgentType.Folder:
                            this.DirectoryTransferView_Show(
                                theParentView,
                                thisAgent);
                            break;
                        default:
                            this.FileTransferView_Show(
                                theParentView,
                                thisAgent);
                            break;
                    }
                }
            }

            if (this._MainView.Status.Equals(MainViewStatus.Started))
            {
                this.PlayAll();
            }
        }

        private void MainView_buttonAddFileTransfer_Click(
            object sender, 
            EventArgs e)
        {
            Application.DoEvents();

            this.FileTransferView_Show(this._MainView);
        }

        private void MainView_buttonAddDirectoryTransfer_Click(
            object sender, 
            EventArgs e)
        {
            Application.DoEvents();

            this.DirectoryTransferView_Show(this._MainView);
        }

        private void MainView_buttonPlayAll_Click(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            this._MainView.Status = MainViewStatus.Started;
        }

        private void MainView_buttonPauseAll_Click(
            object sender, 
            EventArgs e)
        {
            Application.DoEvents();

            this._MainView.Status = MainViewStatus.Paused;
        }

        private void MainView_buttonStopAll_Click(
            object sender, 
            EventArgs e)
        {
            Application.DoEvents();

            this._MainView.Status = MainViewStatus.Stopped;
        }

        private void MainView_buttonSettings_Click(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            this.SettingsView_Show(this._MainView);
        }
        
        private void MainView_buttonCheckForUpdates_Click(
            object sender, 
            EventArgs e)
        {
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                try
                {
                    this._MainView.Cursor =
                        Cursors.WaitCursor;

                    Application.DoEvents();

                    bool IsUpdateAvailable =
                        ApplicationDeployment.CurrentDeployment.CheckForUpdate();

                    if (IsUpdateAvailable)
                    {
                        switch (MessageBox.Show(
                            this._MainView,
                            "An update is available\n\n" +
                                "Do you want to download it now?",
                            this._MainView.Text,
                            MessageBoxButtons.YesNo,
                            MessageBoxIcon.Question,
                            MessageBoxDefaultButton.Button1))
                        {
                            case DialogResult.No:
                                this._MainView.Cursor =
                                    Cursors.Default;

                                Application.DoEvents();
                                return;
                        }

                        Application.DoEvents();

                        ApplicationDeployment.CurrentDeployment.UpdateCompleted +=
                            new AsyncCompletedEventHandler(MainView_CurrentDeployment_UpdateCompleted);

                        ApplicationDeployment.CurrentDeployment.UpdateAsync();
                    }
                    else
                    {
                        MessageBox.Show(
                            this._MainView,
                            "There are no updates available at this time",
                            this._MainView.Text,
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information,
                            MessageBoxDefaultButton.Button1);

                        Application.DoEvents();
                    }
                }
                finally
                {
                    this._MainView.Cursor =
                        Cursors.Default;
                }
            }
        }

        private void MainView_CurrentDeployment_UpdateCompleted(
            object sender,
            AsyncCompletedEventArgs e)
        {
            if (null != e.Error)
            {
                throw e.Error;
            }

            switch (MessageBox.Show(
                this._MainView,
                "The application has been upgraded\n\nDo you want to restart now?",
                "Update Notification",
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Warning,
                MessageBoxDefaultButton.Button1))
            {
                case DialogResult.No:
                    Application.DoEvents();
                    return;
            }

            Application.DoEvents();

            Application.Restart();
        }

        private void MainView_menuitemCheckForUpdates_Click(
            object sender,
            EventArgs e)
        {
            this._MainView.buttonCheckForUpdates.PerformClick();
        }

        private void MainView_menuitemStopAll_Click(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            this._MainView.Status = MainViewStatus.Stopped;
        }

        private void MainView_menuitemPauseAll_Click(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            this._MainView.Status = MainViewStatus.Paused;
        }

        private void MainView_menuitemPlayAll_Click(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            this._MainView.Status = MainViewStatus.Started;
        }

        private void MainView_menuitemExit_Click(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            if (this._MainView.gridTransfers.Rows.Count > 0)
            {
                switch (MessageBox.Show(
                    this._MainView,
                    "Are you sure you want to exit?",
                    this._MainView.Text,
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question,
                    MessageBoxDefaultButton.Button2))
                {
                    case DialogResult.No:
                        return;
                }
            }

            Controller.AbortAndRemoveAllThreads();

            Application.Exit();
        }
        
        private void MainView_Resize(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            if (this._MainView.WindowState.Equals(
                FormWindowState.Minimized))
            {
                this._MainView.NotifyIcon.Visible = true;
                this._MainView.Hide();
            }

            this._MainView.gridTransfers.ClearSelection();
            this._MainView.Refresh();
        }

        private void MainView_NotifyIcon_DoubleClick(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            this._MainView.NotifyIcon.Visible = false;
            this._MainView.Show();
            this._MainView.WindowState = FormWindowState.Normal;
        }

        private void MainView_FormClosing(
            object sender,
            FormClosingEventArgs e)
        {
            Application.DoEvents();

            if (e.CloseReason.Equals(CloseReason.UserClosing))
            {
                MainView theParentView = sender as MainView;

                theParentView.WindowState = FormWindowState.Minimized;

                e.Cancel = true;
                return;
            }

            Controller.AbortAndRemoveAllThreads();
        }
        
        private void MainView_StatusChanged(
            object sender,
            EventArgs e)
        {
            Application.DoEvents();

            MainView theParentView =
                sender as MainView;

            if (null != theParentView)
            {
                switch (theParentView.Status)
                {
                    case MainViewStatus.Paused:
                        this.PauseAll();
                        break;
                    case MainViewStatus.Started:
                        this.PlayAll();
                        break;
                    default:
                        this.StopAll();
                        break;
                }
            }
        }
        #endregion

        #region Private Helpers
        private void PlayAll()
        {
            for (int i = 0; i < this._MainView.gridTransfers.Rows.Count; i++)
            {
                TransferAgent thisAgent =
                    this._MainView.gridTransfers.Rows[i].Tag as TransferAgent;

                if (null != thisAgent)
                {
                    this.StartTransfer(thisAgent);
                }
            }

            lock (this._LockObject)
            {
                if (this._ActiveTransferCount.Equals(0))
                {
                    this._MainView.Status = MainViewStatus.Stopped;

                    this.UpdateControlButtons();
                }
            }
        }

        private void PauseAll()
        {
            for (int i = 0; i < this._MainView.gridTransfers.Rows.Count; i++)
            {
                TransferAgent thisAgent =
                    this._MainView.gridTransfers.Rows[i].Tag as TransferAgent;

                if (null != thisAgent)
                {
                    if (thisAgent.Status.Equals(TransferAgentStatus.Transferring))
                    {
                        thisAgent.Status = TransferAgentStatus.Paused;
                    }
                }
            }

            this.UpdateTitleText("Transfer-o-matic - Paused");
            this.UpdateNotifyIconText("Transfer-o-matic - Paused");
        }

        private void StopAll()
        {
            for (int i = 0; i < this._MainView.gridTransfers.Rows.Count; i++)
            {
                TransferAgent thisAgent =
                    this._MainView.gridTransfers.Rows[i].Tag as TransferAgent;

                if (null != thisAgent)
                {
                    if (thisAgent.Status.Equals(TransferAgentStatus.Transferring))
                    {
                        thisAgent.Status = TransferAgentStatus.Cancelled;
                    }
                }
            }

            this.UpdateTitleText("Transfer-o-matic");
            this.UpdateNotifyIconText("Transfer-o-matic");
        }
        
        public void UpdateNotifyIconText(
            string theCaption)
        {
            // InvokeRequired compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this._MainView.InvokeRequired)
            {
                this._MainView.Invoke(
                    new UpdateNotifyIconTextHandler(this.UpdateNotifyIconText),
                    theCaption);
            }
            else
            {
                this._MainView.NotifyIcon.Text =
                    theCaption;
            }
        }

        public void UpdateTitleText(
            string theCaption)
        {
            // InvokeRequired compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this._MainView.InvokeRequired)
            {
                this._MainView.Invoke(
                    new UpdateTitleTextHandler(this.UpdateTitleText),
                    theCaption);
            }
            else
            {
                this._MainView.Text =
                    theCaption;
            }
        }
        
        public void UpdateStatusBar()
        {
            // InvokeRequired compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this._MainView.InvokeRequired)
            {
                this._MainView.Invoke(
                    new UpdateStatusBarHandler(this.UpdateStatusBar));
            }
            else
            {
                decimal theNumberTransferring = 0;
                decimal theNumberActive = 0;
                decimal theTotalPercentage = 0;

                foreach (DataGridViewRow thisRow in this._MainView.gridTransfers.Rows)
                {
                    TransferAgent thisAgent = thisRow.Tag as TransferAgent;

                    if (null != thisAgent)
                    {
                        if (thisAgent.Status.Equals(TransferAgentStatus.Transferring))
                        {
                            ++theNumberTransferring;
                            theTotalPercentage += thisAgent.TransferredPercentage;
                        }
                        ++theNumberActive;
                    }
                }

                if (theNumberActive.Equals(0))
                {
                    this.UpdateTitleText("Transfer-o-matic");
                    this.UpdateNotifyIconText("Transfer-o-matic");
                }
                else if (!theNumberTransferring.Equals(0))
                {
                    this.UpdateTitleText(
                        String.Format(
                            CultureInfo.CurrentCulture,
                            "Transfer-o-matic - {0}% of {1} transfers{2} completed; {3} pending",
                            Math.Round(theTotalPercentage / theNumberTransferring, 0),
                            theNumberTransferring,
                            theNumberTransferring.Equals(1) ? String.Empty : "s",
                            theNumberActive - theNumberTransferring));
                    this.UpdateNotifyIconText(
                        String.Format(
                            CultureInfo.CurrentCulture,
                            "Transfer-o-matic - {0}% of {1} transfers{2} completed; {3} pending",
                            Math.Round(theTotalPercentage / theNumberTransferring, 0),
                            theNumberTransferring,
                            theNumberTransferring.Equals(1) ? String.Empty : "s",
                            theNumberActive - theNumberTransferring));
                }
            }
        }

        public void UpdateControlButtons()
        {
            // InvokeRequired compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this._MainView.InvokeRequired)
            {
                this._MainView.Invoke(
                    new UpdateControlButtonsHandler(this.UpdateControlButtons));
            }
            else
            {
                this._MainView.buttonPlayAll.Enabled =
                    this._MainView.menuitemPlayAll.Enabled =
                        this._MainView.gridTransfers.Rows.Count > 0;
            }
        }
        #endregion

        #region Delegates
        private delegate void UpdateNotifyIconTextHandler(string theCaption);
        private delegate void UpdateStatusBarHandler();
        private delegate void UpdateTitleTextHandler(string theCaption);
        private delegate void UpdateControlButtonsHandler();
        #endregion
        #endregion
    }
}
